package org.dromara.nursing.service.impl;

import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.dromara.nursing.domain.bo.RoomInfoBo;
import org.dromara.nursing.domain.vo.RoomInfoVo;
import org.dromara.nursing.domain.RoomInfo;
import org.dromara.nursing.mapper.RoomInfoMapper;
import org.dromara.nursing.service.IRoomInfoService;
import org.dromara.nursing.service.IBedInfoService;
import org.dromara.nursing.domain.bo.BedInfoBo;
import org.dromara.nursing.domain.vo.BedInfoVo;
import org.dromara.nursing.controller.BedInfoController;
import org.dromara.common.core.utils.SpringUtils;

import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.ArrayList;
import java.util.Objects;
import org.dromara.nursing.domain.BedInfo;

/**
 * 房间管理Service业务层处理
 *
 * @author Xue
 * @date 2025-04-09
 */
@RequiredArgsConstructor
@Service
public class RoomInfoServiceImpl implements IRoomInfoService {

    private final RoomInfoMapper baseMapper;
    private static final Logger log = LoggerFactory.getLogger(RoomInfoServiceImpl.class);
    private final IBedInfoService bedInfoService;

    /**
     * 查询房间管理
     *
     * @param roomId 主键
     * @return 房间管理
     */
    @Override
    public RoomInfoVo queryById(Long roomId){
        return baseMapper.selectVoById(roomId);
    }

    /**
     * 分页查询房间管理列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 房间管理分页列表
     */
    @Override
    public TableDataInfo<RoomInfoVo> queryPageList(RoomInfoBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<RoomInfo> lqw = buildQueryWrapper(bo);
        Page<RoomInfoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的房间管理列表
     *
     * @param bo 查询条件
     * @return 房间管理列表
     */
    @Override
    public List<RoomInfoVo> queryList(RoomInfoBo bo) {
        LambdaQueryWrapper<RoomInfo> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<RoomInfo> buildQueryWrapper(RoomInfoBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<RoomInfo> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(RoomInfo::getRoomId);
        lqw.eq(StringUtils.isNotBlank(bo.getRoomNumber()), RoomInfo::getRoomNumber, bo.getRoomNumber());
        lqw.eq(StringUtils.isNotBlank(bo.getRoomType()), RoomInfo::getRoomType, bo.getRoomType());
        lqw.eq(StringUtils.isNotBlank(bo.getRoomStatus()), RoomInfo::getRoomStatus, bo.getRoomStatus());
        return lqw;
    }

    /**
     * 新增房间管理
     *
     * @param bo 房间管理
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(RoomInfoBo bo) {
        try {
            log.info("开始新增房间，房间号: {}, 房间类型: {}", bo.getRoomNumber(), bo.getRoomType());

            // 检查房间号是否已存在
            LambdaQueryWrapper<RoomInfo> checkWrapper = Wrappers.lambdaQuery();
            checkWrapper.eq(RoomInfo::getRoomNumber, bo.getRoomNumber());
            long count = baseMapper.selectCount(checkWrapper);
            if (count > 0) {
                log.error("房间号[{}]已存在，不能重复添加", bo.getRoomNumber());
                throw new RuntimeException("房间号已存在，不能重复添加");
            }

            RoomInfo add = MapstructUtils.convert(bo, RoomInfo.class);
            validEntityBeforeSave(add);

            // 根据房间类型自动设置床位数量
            if (add.getBedCount() == null || add.getBedCount() <= 0) {
                // 根据房间类型设置默认床位数
                if ("单人间".equals(add.getRoomType())) {
                    add.setBedCount(1L);
                } else if ("双人间".equals(add.getRoomType())) {
                    add.setBedCount(2L);
                } else if ("三人间".equals(add.getRoomType())) {
                    add.setBedCount(3L);
                } else if ("四人间".equals(add.getRoomType())) {
                    add.setBedCount(4L);
                } else if ("多人间".equals(add.getRoomType())) {
                    add.setBedCount(6L);
                } else {
                    add.setBedCount(1L); // 默认至少有1个床位
                }
                log.info("根据房间类型[{}]自动设置床位数量为: {}", add.getRoomType(), add.getBedCount());
            }

            // 初始可用床位数等于总床位数
            add.setAvailableBeds(add.getBedCount());

            // 设置初始房间状态为可用
            if (add.getRoomStatus() == null || add.getRoomStatus().isEmpty()) {
                add.setRoomStatus("可用");
            }

            log.info("插入房间记录，房间号: {}, 床位数: {}", add.getRoomNumber(), add.getBedCount());
            boolean flag = baseMapper.insert(add) > 0;
            if (flag) {
                bo.setRoomId(add.getRoomId());
                log.info("房间创建成功，roomId: {}", add.getRoomId());

                // 创建对应的床位记录
                createBedsForRoom(add);
            } else {
                log.warn("房间创建失败");
            }
            return flag;
        } catch (Exception e) {
            log.error("新增房间异常", e);
            return false;
        }
    }

    /**
     * 为新增的房间创建床位记录
     *
     * @param roomInfo 房间信息
     */
    private void createBedsForRoom(RoomInfo roomInfo) {
        log.info("开始为房间[{}]创建床位记录，房间ID: {}, 床位总数: {}", roomInfo.getRoomNumber(), roomInfo.getRoomId(), roomInfo.getBedCount());

        if (roomInfo.getBedCount() == null || roomInfo.getBedCount() <= 0) {
            log.warn("房间床位数量无效: {}, 不创建床位记录", roomInfo.getBedCount());
            return;
        }

        try {
            // 根据床位数量创建床位记录
            int successCount = 0;
            List<BedInfoBo> bedInfoList = new ArrayList<>();

            // 先确定需要创建的床位数量
            int bedCount = roomInfo.getBedCount().intValue();
            log.info("需要为房间[{}]创建{}个床位", roomInfo.getRoomNumber(), bedCount);

            // 准备所有床位数据
            for (int i = 1; i <= bedCount; i++) {
                // 为每个床位创建一个新的BedInfoBo对象
                BedInfoBo bedInfoBo = new BedInfoBo();
                bedInfoBo.setRoomId(roomInfo.getRoomId());
                bedInfoBo.setRoomNumber(roomInfo.getRoomNumber());
                // 床位号格式：房间号-序号（保证一致性）
                String bedNumber = roomInfo.getRoomNumber() + "-" + i;
                bedInfoBo.setBedNumber(bedNumber);
                // 初始状态为"空闲"
                bedInfoBo.setBedStatus("空闲");
                bedInfoBo.setRemarks("系统自动创建");

                log.info("准备创建床位: {}, 房间ID: {}", bedNumber, roomInfo.getRoomId());
                bedInfoList.add(bedInfoBo);
            }

            // 批量插入所有床位记录
            for (BedInfoBo bedInfoBo : bedInfoList) {
                try {
                    boolean result = bedInfoService.insertByBo(bedInfoBo);
                    if (result) {
                        successCount++;
                        log.info("床位创建成功: {}, bedId={}", bedInfoBo.getBedNumber(), bedInfoBo.getBedId());
                    } else {
                        log.warn("床位创建失败: {}", bedInfoBo.getBedNumber());
                    }
                } catch (Exception e) {
                    log.error("创建床位[{}]异常: {}", bedInfoBo.getBedNumber(), e.getMessage(), e);
                }
            }

            log.info("床位创建完成，成功: {}/{}, 房间ID: {}", successCount, bedCount, roomInfo.getRoomId());
            
            // 如果创建的床位数与预期不一致，更新房间的床位数和可用床位数
            if (successCount != bedCount) {
                log.warn("创建的床位数量[{}]与预期[{}]不一致，更新房间记录", successCount, bedCount);
                RoomInfo updateRoom = new RoomInfo();
                updateRoom.setRoomId(roomInfo.getRoomId());
                updateRoom.setBedCount((long) successCount);
                updateRoom.setAvailableBeds((long) successCount);
                baseMapper.updateById(updateRoom);
            }
        } catch (Exception e) {
            log.error("创建床位记录异常", e);
        }
    }

    /**
     * 修改房间管理
     *
     * @param bo 房间管理
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(RoomInfoBo bo) {
        RoomInfo update = MapstructUtils.convert(bo, RoomInfo.class);
        validEntityBeforeSave(update);

        // 获取原房间信息，用于判断状态是否变更
        RoomInfo oldRoom = baseMapper.selectById(update.getRoomId());
        boolean result = baseMapper.updateById(update) > 0;

        // 如果更新成功且房间状态发生变化
        if (result && oldRoom != null && !Objects.equals(oldRoom.getRoomStatus(), update.getRoomStatus())) {
            // 如果房间状态变为"维修中"，则将所有床位状态也设置为"维修中"
            if ("维修中".equals(update.getRoomStatus())) {
                updateBedsStatus(update.getRoomId(), "维修中");
            }
            // 如果房间状态从"维修中"变为"可用"，则将所有床位状态设置为"空闲"
            else if ("维修中".equals(oldRoom.getRoomStatus()) && "可用".equals(update.getRoomStatus())) {
                updateBedsStatus(update.getRoomId(), "空闲");
            }
        }

        return result;
    }

    /**
     * 更新房间下所有床位的状态
     *
     * @param roomId 房间ID
     * @param status 新的床位状态
     */
    private void updateBedsStatus(Long roomId, String status) {
        try {
            log.info("更新房间[{}]下所有床位状态为: {}", roomId, status);
            LambdaQueryWrapper<BedInfo> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(BedInfo::getRoomId, roomId);
            
            // 如果目标状态是"维修中"，则所有床位都设置为维修中
            // 如果目标状态是"可用"，只有当前状态为"维修中"的床位才设置为"空闲"
            if ("维修中".equals(status)) {
                // 所有床位变为维修中
                List<BedInfo> bedList = bedInfoService.getBaseMapper().selectList(queryWrapper);
                
                for (BedInfo bed : bedList) {
                    // 如果床位已被占用，需要特殊处理
                    if ("已占用".equals(bed.getBedStatus())) {
                        log.warn("床位[{}]已被占用，不能设置为维修中", bed.getBedNumber());
                        continue;
                    }
                    
                    // 更新床位状态
                    BedInfo updateBed = new BedInfo();
                    updateBed.setBedId(bed.getBedId());
                    updateBed.setBedStatus(status);
                    bedInfoService.getBaseMapper().updateById(updateBed);
                    log.info("床位[{}]状态更新为: {}", bed.getBedNumber(), status);
                }
            } else if ("可用".equals(status)) {
                // 只将维修中的床位改为空闲
                queryWrapper.eq(BedInfo::getBedStatus, "维修中");
                List<BedInfo> bedList = bedInfoService.getBaseMapper().selectList(queryWrapper);
                
                for (BedInfo bed : bedList) {
                    BedInfo updateBed = new BedInfo();
                    updateBed.setBedId(bed.getBedId());
                    updateBed.setBedStatus("空闲");
                    bedInfoService.getBaseMapper().updateById(updateBed);
                    log.info("床位[{}]状态从维修中更新为: 空闲", bed.getBedNumber());
                }
            }
            
            // 更新完床位状态后，计算可用床位数
            updateAvailableBeds(roomId);
        } catch (Exception e) {
            log.error("更新床位状态异常", e);
        }
    }

    /**
     * 更新房间可用床位数
     *
     * @param roomId 房间ID
     */
    private void updateAvailableBeds(Long roomId) {
        try {
            log.info("开始更新房间[{}]的可用床位数", roomId);
            
            // 查询房间总床位数
            RoomInfo roomInfo = baseMapper.selectById(roomId);
            if (roomInfo == null) {
                log.warn("未找到房间[{}]，无法更新可用床位数", roomId);
                return;
            }
            
            // 查询所有床位状态
            LambdaQueryWrapper<BedInfo> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(BedInfo::getRoomId, roomId);
            List<BedInfo> allBeds = bedInfoService.getBaseMapper().selectList(queryWrapper);
            
            // 统计各种状态的床位数
            long totalBeds = allBeds.size();
            long occupiedBeds = allBeds.stream().filter(bed -> "已占用".equals(bed.getBedStatus())).count();
            long maintenanceBeds = allBeds.stream().filter(bed -> "维修中".equals(bed.getBedStatus())).count();
            long availableBeds = allBeds.stream().filter(bed -> "空闲".equals(bed.getBedStatus())).count();
            
            log.info("房间[{}]床位统计：总数={}, 已占用={}, 维修中={}, 空闲={}", 
                    roomId, totalBeds, occupiedBeds, maintenanceBeds, availableBeds);
            
            // 更新房间信息
            roomInfo.setAvailableBeds(availableBeds);
            
            // 根据床位状态更新房间状态
            if (maintenanceBeds > 0 && maintenanceBeds == totalBeds) {
                // 所有床位都在维修中
                roomInfo.setRoomStatus("维修中");
                log.info("所有床位都在维修中，将房间状态设置为'维修中'");
            } else if (availableBeds == 0) {
                // 没有可用床位
                roomInfo.setRoomStatus("已满");
                log.info("没有可用床位，将房间状态设置为'已满'");
            } else if (availableBeds < totalBeds) {
                // 部分床位可用
                roomInfo.setRoomStatus("可用");
                log.info("部分床位可用({}/{})，将房间状态设置为'可用'", availableBeds, totalBeds);
            } else {
                // 所有床位都可用
                roomInfo.setRoomStatus("可用");
                log.info("所有床位都可用，将房间状态设置为'可用'");
            }
            
            // 更新床位总数，确保与实际数量一致
            if (roomInfo.getBedCount() != totalBeds) {
                log.warn("房间[{}]记录的床位总数[{}]与实际床位数[{}]不一致，进行更新", 
                        roomId, roomInfo.getBedCount(), totalBeds);
                roomInfo.setBedCount(totalBeds);
            }
            
            // 保存房间信息更新
            baseMapper.updateById(roomInfo);
            log.info("房间[{}]信息已更新：总床位数={}, 可用床位数={}, 状态={}", 
                    roomId, roomInfo.getBedCount(), roomInfo.getAvailableBeds(), roomInfo.getRoomStatus());
        } catch (Exception e) {
            log.error("更新房间可用床位数异常", e);
        }
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(RoomInfo entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除房间管理信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        try {
            log.info("开始删除房间记录，ids: {}", ids);

            if (isValid) {
                // 检查房间是否有床位被占用
                for (Long id : ids) {
                    // 查询房间下的床位
                    BedInfoBo queryBo = new BedInfoBo();
                    queryBo.setRoomId(id);
                    List<BedInfoVo> bedList = bedInfoService.queryList(queryBo);

                    // 检查是否有床位被占用
                    for (BedInfoVo bed : bedList) {
                        if ("已占用".equals(bed.getBedStatus())) {
                            log.warn("房间[{}]下有床位[{}]已被占用，不能删除", id, bed.getBedNumber());
                            return false;
                        }
                    }

                    // 先删除房间下的所有床位
                    if (!bedList.isEmpty()) {
                        List<Long> bedIds = bedList.stream().map(BedInfoVo::getBedId).toList();
                        log.info("删除房间[{}]下的床位，bedIds: {}", id, bedIds);
                        bedInfoService.deleteWithValidByIds(bedIds, false);
                    }
                }
            }

            // 删除房间
            int rows = baseMapper.deleteBatchIds(ids);
            boolean success = rows > 0;
            log.info("删除房间记录结果: {}, 影响行数: {}", success, rows);
            return success;
        } catch (Exception e) {
            log.error("删除房间记录异常", e);
            return false;
        }
    }
}
